package cspmodel

import (
	"fmt"
	"io"
	"net/http"
	"time"
)

/*
barrier 屏障模式故名思义就是一种屏障，用来阻塞直到聚合所有 goroutine 返回结果
*/
var (
	client = http.Client{
		Timeout: time.Duration(3 * time.Second),
	}
)

type SiteResp struct {
	Site   string // 网站
	Err    error  // 错误信息
	Resp   string // 响应
	Status int    // 状态
	Cost   int64  // 耗时
}

func BarrierMode() {
	endpoints := []string{
		"https://www.baidu.com",
		"https://segmentfault.com/",
		"https://blog.csdn.net/",
		"https://www.jd.com/",
	}

	// 一个endpoints返回一个结果
	respChan := make(chan SiteResp, len(endpoints))
	defer close(respChan)

	// 并行爬取
	for _, endpoint := range endpoints {
		go doSiteRequest(respChan, endpoint)
	}

	// 阻塞直到聚合结果完成
	down := make(chan struct{})                // 结束标志
	ret := make([]SiteResp, 0, len(endpoints)) //
	go mergeResponse(respChan, &ret, down)

	// 等待结束
	<-down

	for _, v := range ret {
		fmt.Printf("%+v\n", v)
	}
}

// 接收chan里的网站响应，聚合放入到ret
func mergeResponse(resp <-chan SiteResp, ret *[]SiteResp, down chan<- struct{}) {
	defer func() {
		down <- struct{}{}
	}()

	count := 0
	for v := range resp {
		*ret = append(*ret, v)
		count++

		// 填充完成,  返回
		if count == cap(*ret) {
			return
		}
	}

}

// 访问网站将响应写到chan里
func doSiteRequest(out chan<- SiteResp, url string) {
	res := SiteResp{
		Site: url,
	}
	startAt := time.Now()

	defer func() {
		res.Cost = time.Since(startAt).Milliseconds()
		out <- res
	}()

	// 爬取网页
	resp, err := client.Get(url)
	if resp != nil {
		res.Status = resp.StatusCode
	}

	if err != nil {
		res.Err = err
		return
	}

	// 暂不处理结果
	_, err = io.ReadAll(resp.Body)
	defer resp.Body.Close()
	if err != nil {
		res.Err = err
		return
	}

	//res.Resp = string(byt)
}
